/*
*    へ　　　　　  ／|
*    /＼7　　   ∠＿/
*    /　│　　 ／　／               
*    │　Z ＿,＜　／　　 /`ヽ     
*    │　　　　　ヽ　　 /　　〉    
*    Y　　　　　  `  /　　/     
*    ｲ ●　､　●　⊂⊃〈　　/       
*    ()  へ　　　　 |　＼       
*    >ｰ ､_　 ィ　 │ ／／        | @author:smily
*    / へ　　 /　ﾉ＜| ＼＼       | @project:net-hole
*    ヽ_ﾉ　　(_／　 │／／        | @file: MySocket.cpp
*    7　　　　　　　|／          | @time: 2020/12/29 11:02
*====＞―r￣￣`ｰ―＿===========    
*^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/

#include "../include/MySocket.h"
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#include <arpa/inet.h>

MySocket::MySocket()
{
}


MySocket::~MySocket()
{
}

bool MySocket::init_socket()
{
    if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < -1) {
        snprintf(err_msg, sizeof(err_msg), "create socket error:%s(srrno:%d)\n",strerror(errno),errno);
    }
    return true;
}

char* MySocket::get_err_msg()
{
    return err_msg;
}

bool MySocketServer::create_server(unsigned int port)
{
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
    server_addr.sin_port = htons(port);
    flags = fcntl(socket_fd, F_GETFL, 0);
    fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);//设置为非阻塞
    //设置超时
    struct timeval timeout = { 3,0 };//3s
    if (setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)) != 0){
        snprintf(err_msg, sizeof(err_msg), "set send timeout failed: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) != 0) {
        snprintf(err_msg, sizeof(err_msg), "set recv timeout failed: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    //设置重用地址，防止Address already in use
    int on = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    //将本地地址绑定到所创建的套接字上
    if (bind(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        snprintf(err_msg, sizeof(err_msg), "bind socket error: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    //开始监听是否有客户端连接
    if (listen(socket_fd, 10) == -1) {
        snprintf(err_msg, sizeof(err_msg), "listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    return true;
}


bool MySocketServer::accept_client(int & client_socket)
{
    struct sockaddr_in client_addr;
    socklen_t client_len;
    client_socket = accept(socket_fd, (struct sockaddr*)&client_addr, &client_len);
    if (client_socket < 0)
    {
        snprintf(err_msg, sizeof(err_msg), "accept socket error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    client_fd = client_socket;
    return true;
}

bool MySocketServer::recv_data(char * buffer, int buffer_len, int & recv_len)
{
    memset(buffer, 0, buffer_len);
    recv_len = recv(client_fd, buffer, buffer_len, 0);
    if (recv_len <= 0){
        snprintf(err_msg, sizeof(err_msg), "recv data error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    printf("server recv:%s\n", buffer);
    return true;
}

bool MySocketServer::send_data(const char * data, int len)
{
    if (send(client_fd, data, len, 0) == -1) {
        snprintf(err_msg, sizeof(err_msg), "send data error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }

    return true;
}

void MySocketServer::close_client(int client_socket)
{
    close(client_socket);
}

void MySocketServer::close_server()
{
    close(socket_fd);
}

bool MySocketClient::client_connect(const char * ip, unsigned int port)
{
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    if (inet_pton(AF_INET, ip, &server_addr.sin_addr) <= 0) {
        snprintf(err_msg, sizeof(err_msg), "inet_pton error for %s\n", ip);
        return false;
    }

    if (connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        snprintf(err_msg, sizeof(err_msg), "connect error: %s(errno: %d)\n", strerror(errno), errno);
        return false;
    }
    return true;
}

bool MySocketClient::recv_data(char * buffer, int buffer_len, int & recv_len)
{
    memset(buffer, 0, buffer_len);
    if ((recv_len = recv(socket_fd, buffer, buffer_len, 0)) == -1) {
        snprintf(err_msg, sizeof(err_msg), "recv data error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    buffer[buffer_len] = '\0';
    printf("client recv:%s\n", buffer);
    return true;
}

bool MySocketClient::send_data(const char * data, int len)
{
    if (send(socket_fd, data, len, 0) < 0) {
        snprintf(err_msg, sizeof(err_msg), "send data error: %s(errno: %d)", strerror(errno), errno);
        return false;
    }
    return true;
}

void MySocketClient::client_close()
{
    close(socket_fd);
}
